# -*- Mode: Python -*-
# vim: filetype=python
#
# Copyright (C) 2018 Red Hat, Inc.
#
# Authors:
#  Daniel P. Berrange <berrange@redhat.com>
#  Laszlo Ersek <lersek@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.

##
# = Firmware
##

{ 'include' : 'machine.json' }
{ 'include' : 'block-core.json' }

##
# @FirmwareOSInterface:
#
# Lists the firmware-OS interface types provided by various firmware
# that is commonly used with QEMU virtual machines.
#
# @bios: Traditional x86 BIOS interface. For example, firmware built
#        from the SeaBIOS project usually provides this interface.
#
# @openfirmware: The interface is defined by the (historical) IEEE
#                1275-1994 standard. Examples for firmware projects that
#                provide this interface are: OpenBIOS and SLOF.
#
# @uboot: Firmware interface defined by the U-Boot project.
#
# @uefi: Firmware interface defined by the UEFI specification. For
#        example, firmware built from the edk2 (EFI Development Kit II)
#        project usually provides this interface.
#
# Since: 3.0
##
{ 'enum' : 'FirmwareOSInterface',
  'data' : [ 'bios', 'openfirmware', 'uboot', 'uefi' ] }

##
# @FirmwareDevice:
#
# Defines the device types that firmware can be mapped into.
#
# @flash: The firmware executable and its accompanying NVRAM file are to
#         be mapped into a pflash chip each.
#
# @kernel: The firmware is to be loaded like a Linux kernel. This is
#          similar to @memory but may imply additional processing that
#          is specific to the target architecture and machine type.
#
# @memory: The firmware is to be mapped into memory.
#
# Since: 3.0
##
{ 'enum' : 'FirmwareDevice',
  'data' : [ 'flash', 'kernel', 'memory' ] }

##
# @FirmwareTarget:
#
# Defines the machine types that firmware may execute on.
#
# @architecture: Determines the emulation target (the QEMU system
#                emulator) that can execute the firmware.
#
# @machines: Lists the machine types (known by the emulator that is
#            specified through @architecture) that can execute the
#            firmware. Elements of @machines are supposed to be concrete
#            machine types, not aliases. Glob patterns are understood,
#            which is especially useful for versioned machine types.
#            (For example, the glob pattern "pc-i440fx-*" matches
#            "pc-i440fx-2.12".) On the QEMU command line, "-machine
#            type=..." specifies the requested machine type (but that
#            option does not accept glob patterns).
#
# Since: 3.0
##
{ 'struct' : 'FirmwareTarget',
  'data'   : { 'architecture' : 'SysEmuTarget',
               'machines'     : [ 'str' ] } }

##
# @FirmwareFeature:
#
# Defines the features that firmware may support, and the platform
# requirements that firmware may present.
#
# @acpi-s3: The firmware supports S3 sleep (suspend to RAM), as defined
#           in the ACPI specification. On the "pc-i440fx-*" machine
#           types of the @i386 and @x86_64 emulation targets, S3 can be
#           enabled with "-global PIIX4_PM.disable_s3=0" and disabled
#           with "-global PIIX4_PM.disable_s3=1". On the "pc-q35-*"
#           machine types of the @i386 and @x86_64 emulation targets, S3
#           can be enabled with "-global ICH9-LPC.disable_s3=0" and
#           disabled with "-global ICH9-LPC.disable_s3=1".
#
# @acpi-s4: The firmware supports S4 hibernation (suspend to disk), as
#           defined in the ACPI specification. On the "pc-i440fx-*"
#           machine types of the @i386 and @x86_64 emulation targets, S4
#           can be enabled with "-global PIIX4_PM.disable_s4=0" and
#           disabled with "-global PIIX4_PM.disable_s4=1". On the
#           "pc-q35-*" machine types of the @i386 and @x86_64 emulation
#           targets, S4 can be enabled with "-global
#           ICH9-LPC.disable_s4=0" and disabled with "-global
#           ICH9-LPC.disable_s4=1".
#
# @amd-sev: The firmware supports running under AMD Secure Encrypted
#           Virtualization, as specified in the AMD64 Architecture
#           Programmer's Manual. QEMU command line options related to
#           this feature are documented in
#           "docs/amd-memory-encryption.txt".
#
# @amd-sev-es: The firmware supports running under AMD Secure Encrypted
#              Virtualization - Encrypted State, as specified in the AMD64
#              Architecture Programmer's Manual. QEMU command line options
#              related to this feature are documented in
#              "docs/amd-memory-encryption.txt".
#
# @enrolled-keys: The variable store (NVRAM) template associated with
#                 the firmware binary has the UEFI Secure Boot
#                 operational mode turned on, with certificates
#                 enrolled.
#
# @requires-smm: The firmware requires the platform to emulate SMM
#                (System Management Mode), as defined in the AMD64
#                Architecture Programmer's Manual, and in the Intel(R)64
#                and IA-32 Architectures Software Developer's Manual. On
#                the "pc-q35-*" machine types of the @i386 and @x86_64
#                emulation targets, SMM emulation can be enabled with
#                "-machine smm=on". (On the "pc-q35-*" machine types of
#                the @i386 emulation target, @requires-smm presents
#                further CPU requirements; one combination known to work
#                is "-cpu coreduo,nx=off".) If the firmware is marked as
#                both @secure-boot and @requires-smm, then write
#                accesses to the pflash chip (NVRAM) that holds the UEFI
#                variable store must be restricted to code that executes
#                in SMM, using the additional option "-global
#                driver=cfi.pflash01,property=secure,value=on".
#                Furthermore, a large guest-physical address space
#                (comprising guest RAM, memory hotplug range, and 64-bit
#                PCI MMIO aperture), and/or a high VCPU count, may
#                present high SMRAM requirements from the firmware. On
#                the "pc-q35-*" machine types of the @i386 and @x86_64
#                emulation targets, the SMRAM size may be increased
#                above the default 16MB with the "-global
#                mch.extended-tseg-mbytes=uint16" option. As a rule of
#                thumb, the default 16MB size suffices for 1TB of
#                guest-phys address space and a few tens of VCPUs; for
#                every further TB of guest-phys address space, add 8MB
#                of SMRAM. 48MB should suffice for 4TB of guest-phys
#                address space and 2-3 hundred VCPUs.
#
# @secure-boot: The firmware implements the software interfaces for UEFI
#               Secure Boot, as defined in the UEFI specification. Note
#               that without @requires-smm, guest code running with
#               kernel privileges can undermine the security of Secure
#               Boot.
#
# @verbose-dynamic: When firmware log capture is enabled, the firmware
#                   logs a large amount of debug messages, which may
#                   impact boot performance. With log capture disabled,
#                   there is no boot performance impact. On the
#                   "pc-i440fx-*" and "pc-q35-*" machine types of the
#                   @i386 and @x86_64 emulation targets, firmware log
#                   capture can be enabled with the QEMU command line
#                   options "-chardev file,id=fwdebug,path=LOGFILEPATH
#                   -device isa-debugcon,iobase=0x402,chardev=fwdebug".
#                   @verbose-dynamic is mutually exclusive with
#                   @verbose-static.
#
# @verbose-static: The firmware unconditionally produces a large amount
#                  of debug messages, which may impact boot performance.
#                  This feature may typically be carried by certain UEFI
#                  firmware for the "virt-*" machine types of the @arm
#                  and @aarch64 emulation targets, where the debug
#                  messages are written to the first (always present)
#                  PL011 UART. @verbose-static is mutually exclusive
#                  with @verbose-dynamic.
#
# Since: 3.0
##
{ 'enum' : 'FirmwareFeature',
  'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'amd-sev-es', 'enrolled-keys',
             'requires-smm', 'secure-boot', 'verbose-dynamic',
             'verbose-static' ] }

##
# @FirmwareFlashFile:
#
# Defines common properties that are necessary for loading a firmware
# file into a pflash chip. The corresponding QEMU command line option is
# "-drive file=@filename,format=@format". Note however that the
# option-argument shown here is incomplete; it is completed under
# @FirmwareMappingFlash.
#
# @filename: Specifies the filename on the host filesystem where the
#            firmware file can be found.
#
# @format: Specifies the block format of the file pointed-to by
#          @filename, such as @raw or @qcow2.
#
# Since: 3.0
##
{ 'struct' : 'FirmwareFlashFile',
  'data'   : { 'filename' : 'str',
               'format'   : 'BlockdevDriver' } }

##
# @FirmwareMappingFlash:
#
# Describes loading and mapping properties for the firmware executable
# and its accompanying NVRAM file, when @FirmwareDevice is @flash.
#
# @executable: Identifies the firmware executable. The firmware
#              executable may be shared by multiple virtual machine
#              definitions. The preferred corresponding QEMU command
#              line options are
#                  -drive if=none,id=pflash0,readonly=on,file=@executable.@filename,format=@executable.@format
#                  -machine pflash0=pflash0
#              or equivalent -blockdev instead of -drive.
#              With QEMU versions older than 4.0, you have to use
#                  -drive if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format
#
# @nvram-template: Identifies the NVRAM template compatible with
#                  @executable. Management software instantiates an
#                  individual copy -- a specific NVRAM file -- from
#                  @nvram-template.@filename for each new virtual
#                  machine definition created. @nvram-template.@filename
#                  itself is never mapped into virtual machines, only
#                  individual copies of it are. An NVRAM file is
#                  typically used for persistently storing the
#                  non-volatile UEFI variables of a virtual machine
#                  definition. The preferred corresponding QEMU
#                  command line options are
#                      -drive if=none,id=pflash1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format
#                      -machine pflash1=pflash1
#                  or equivalent -blockdev instead of -drive.
#                  With QEMU versions older than 4.0, you have to use
#                      -drive if=pflash,unit=1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format
#
# Since: 3.0
##
{ 'struct' : 'FirmwareMappingFlash',
  'data'   : { 'executable'     : 'FirmwareFlashFile',
               'nvram-template' : 'FirmwareFlashFile' } }

##
# @FirmwareMappingKernel:
#
# Describes loading and mapping properties for the firmware executable,
# when @FirmwareDevice is @kernel.
#
# @filename: Identifies the firmware executable. The firmware executable
#            may be shared by multiple virtual machine definitions. The
#            corresponding QEMU command line option is "-kernel
#            @filename".
#
# Since: 3.0
##
{ 'struct' : 'FirmwareMappingKernel',
  'data'   : { 'filename' : 'str' } }

##
# @FirmwareMappingMemory:
#
# Describes loading and mapping properties for the firmware executable,
# when @FirmwareDevice is @memory.
#
# @filename: Identifies the firmware executable. The firmware executable
#            may be shared by multiple virtual machine definitions. The
#            corresponding QEMU command line option is "-bios
#            @filename".
#
# Since: 3.0
##
{ 'struct' : 'FirmwareMappingMemory',
  'data'   : { 'filename' : 'str' } }

##
# @FirmwareMapping:
#
# Provides a discriminated structure for firmware to describe its
# loading / mapping properties.
#
# @device: Selects the device type that the firmware must be mapped
#          into.
#
# Since: 3.0
##
{ 'union'         : 'FirmwareMapping',
  'base'          : { 'device' : 'FirmwareDevice' },
  'discriminator' : 'device',
  'data'          : { 'flash'  : 'FirmwareMappingFlash',
                      'kernel' : 'FirmwareMappingKernel',
                      'memory' : 'FirmwareMappingMemory' } }

##
# @Firmware:
#
# Describes a firmware (or a firmware use case) to management software.
#
# It is possible for multiple @Firmware elements to match the search
# criteria of management software. Applications thus need rules to pick
# one of the many matches, and users need the ability to override distro
# defaults.
#
# It is recommended to create firmware JSON files (each containing a
# single @Firmware root element) with a double-digit prefix, for example
# "50-ovmf.json", "50-seabios-256k.json", etc, so they can be sorted in
# predictable order. The firmware JSON files should be searched for in
# three directories:
#
#   - /usr/share/qemu/firmware -- populated by distro-provided firmware
#                                 packages (XDG_DATA_DIRS covers
#                                 /usr/share by default),
#
#   - /etc/qemu/firmware -- exclusively for sysadmins' local additions,
#
#   - $XDG_CONFIG_HOME/qemu/firmware -- exclusively for per-user local
#                                       additions (XDG_CONFIG_HOME
#                                       defaults to $HOME/.config).
#
# Top-down, the list of directories goes from general to specific.
#
# Management software should build a list of files from all three
# locations, then sort the list by filename (i.e., last pathname
# component). Management software should choose the first JSON file on
# the sorted list that matches the search criteria. If a more specific
# directory has a file with same name as a less specific directory, then
# the file in the more specific directory takes effect. If the more
# specific file is zero length, it hides the less specific one.
#
# For example, if a distro ships
#
#   - /usr/share/qemu/firmware/50-ovmf.json
#
#   - /usr/share/qemu/firmware/50-seabios-256k.json
#
# then the sysadmin can prevent the default OVMF being used at all with
#
#   $ touch /etc/qemu/firmware/50-ovmf.json
#
# The sysadmin can replace/alter the distro default OVMF with
#
#   $ vim /etc/qemu/firmware/50-ovmf.json
#
# or they can provide a parallel OVMF with higher priority
#
#   $ vim /etc/qemu/firmware/10-ovmf.json
#
# or they can provide a parallel OVMF with lower priority
#
#   $ vim /etc/qemu/firmware/99-ovmf.json
#
# @description: Provides a human-readable description of the firmware.
#               Management software may or may not display @description.
#
# @interface-types: Lists the types of interfaces that the firmware can
#                   expose to the guest OS. This is a non-empty, ordered
#                   list; entries near the beginning of @interface-types
#                   are considered more native to the firmware, and/or
#                   to have a higher quality implementation in the
#                   firmware, than entries near the end of
#                   @interface-types.
#
# @mapping: Describes the loading / mapping properties of the firmware.
#
# @targets: Collects the target architectures (QEMU system emulators)
#           and their machine types that may execute the firmware.
#
# @features: Lists the features that the firmware supports, and the
#            platform requirements it presents.
#
# @tags: A list of auxiliary strings associated with the firmware for
#        which @description is not appropriate, due to the latter's
#        possible exposure to the end-user. @tags serves development and
#        debugging purposes only, and management software shall
#        explicitly ignore it.
#
# Since: 3.0
#
# Examples:
#
# {
#     "description": "SeaBIOS",
#     "interface-types": [
#         "bios"
#     ],
#     "mapping": {
#         "device": "memory",
#         "filename": "/usr/share/seabios/bios-256k.bin"
#     },
#     "targets": [
#         {
#             "architecture": "i386",
#             "machines": [
#                 "pc-i440fx-*",
#                 "pc-q35-*"
#             ]
#         },
#         {
#             "architecture": "x86_64",
#             "machines": [
#                 "pc-i440fx-*",
#                 "pc-q35-*"
#             ]
#         }
#     ],
#     "features": [
#         "acpi-s3",
#         "acpi-s4"
#     ],
#     "tags": [
#         "CONFIG_BOOTSPLASH=n",
#         "CONFIG_ROM_SIZE=256",
#         "CONFIG_USE_SMM=n"
#     ]
# }
#
# {
#     "description": "OVMF with SB+SMM, empty varstore",
#     "interface-types": [
#         "uefi"
#     ],
#     "mapping": {
#         "device": "flash",
#         "executable": {
#             "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd",
#             "format": "raw"
#         },
#         "nvram-template": {
#             "filename": "/usr/share/OVMF/OVMF_VARS.fd",
#             "format": "raw"
#         }
#     },
#     "targets": [
#         {
#             "architecture": "x86_64",
#             "machines": [
#                 "pc-q35-*"
#             ]
#         }
#     ],
#     "features": [
#         "acpi-s3",
#         "amd-sev",
#         "requires-smm",
#         "secure-boot",
#         "verbose-dynamic"
#     ],
#     "tags": [
#         "-a IA32",
#         "-a X64",
#         "-p OvmfPkg/OvmfPkgIa32X64.dsc",
#         "-t GCC48",
#         "-b DEBUG",
#         "-D SMM_REQUIRE",
#         "-D SECURE_BOOT_ENABLE",
#         "-D FD_SIZE_4MB"
#     ]
# }
#
# {
#     "description": "OVMF with SB+SMM, SB enabled, MS certs enrolled",
#     "interface-types": [
#         "uefi"
#     ],
#     "mapping": {
#         "device": "flash",
#         "executable": {
#             "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd",
#             "format": "raw"
#         },
#         "nvram-template": {
#             "filename": "/usr/share/OVMF/OVMF_VARS.secboot.fd",
#             "format": "raw"
#         }
#     },
#     "targets": [
#         {
#             "architecture": "x86_64",
#             "machines": [
#                 "pc-q35-*"
#             ]
#         }
#     ],
#     "features": [
#         "acpi-s3",
#         "amd-sev",
#         "enrolled-keys",
#         "requires-smm",
#         "secure-boot",
#         "verbose-dynamic"
#     ],
#     "tags": [
#         "-a IA32",
#         "-a X64",
#         "-p OvmfPkg/OvmfPkgIa32X64.dsc",
#         "-t GCC48",
#         "-b DEBUG",
#         "-D SMM_REQUIRE",
#         "-D SECURE_BOOT_ENABLE",
#         "-D FD_SIZE_4MB"
#     ]
# }
#
# {
#     "description": "OVMF with SEV-ES support",
#     "interface-types": [
#         "uefi"
#     ],
#     "mapping": {
#         "device": "flash",
#         "executable": {
#             "filename": "/usr/share/OVMF/OVMF_CODE.fd",
#             "format": "raw"
#         },
#         "nvram-template": {
#             "filename": "/usr/share/OVMF/OVMF_VARS.fd",
#             "format": "raw"
#         }
#     },
#     "targets": [
#         {
#             "architecture": "x86_64",
#             "machines": [
#                 "pc-q35-*"
#             ]
#         }
#     ],
#     "features": [
#         "acpi-s3",
#         "amd-sev",
#         "amd-sev-es",
#         "verbose-dynamic"
#     ],
#     "tags": [
#         "-a X64",
#         "-p OvmfPkg/OvmfPkgX64.dsc",
#         "-t GCC48",
#         "-b DEBUG",
#         "-D FD_SIZE_4MB"
#     ]
# }
#
# {
#     "description": "UEFI firmware for ARM64 virtual machines",
#     "interface-types": [
#         "uefi"
#     ],
#     "mapping": {
#         "device": "flash",
#         "executable": {
#             "filename": "/usr/share/AAVMF/AAVMF_CODE.fd",
#             "format": "raw"
#         },
#         "nvram-template": {
#             "filename": "/usr/share/AAVMF/AAVMF_VARS.fd",
#             "format": "raw"
#         }
#     },
#     "targets": [
#         {
#             "architecture": "aarch64",
#             "machines": [
#                 "virt-*"
#             ]
#         }
#     ],
#     "features": [
#
#     ],
#     "tags": [
#         "-a AARCH64",
#         "-p ArmVirtPkg/ArmVirtQemu.dsc",
#         "-t GCC48",
#         "-b DEBUG",
#         "-D DEBUG_PRINT_ERROR_LEVEL=0x80000000"
#     ]
# }
##
{ 'struct' : 'Firmware',
  'data'   : { 'description'     : 'str',
               'interface-types' : [ 'FirmwareOSInterface' ],
               'mapping'         : 'FirmwareMapping',
               'targets'         : [ 'FirmwareTarget' ],
               'features'        : [ 'FirmwareFeature' ],
               'tags'            : [ 'str' ] } }
